package fgin

import (
	"errors"
	"reflect"
	"strings"

	"github.com/go-playground/locales/en"
	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	en_translations "github.com/go-playground/validator/v10/translations/en"
	zh_translations "github.com/go-playground/validator/v10/translations/zh"
)

// 全局翻译器缓存
var (
	validate *validator.Validate
	uni      *ut.UniversalTranslator
	trans    ut.Translator
)

// 初始化校验器
func initValidator() {
	if fginConfig.Validator == "" {
		// 未配置校验器
		logSuger.Info("未配置validator项,使用默认en校验器")
		fginConfig.Validator = "en"
	}
	locale := fginConfig.Validator
	// 初始化校验器
	validate = validator.New()
	// 根据语言选择翻译器
	switch locale {
	case "zh":
		zhValidator()
	case "en":
		enValidator()
	default:
		panic("校验器不支持当前语言:" + locale)
	}
}

// 中文翻译器注册到校验器中
func zhValidator() {
	zh := zh.New()
	uni = ut.New(zh, zh)
	transTemp, _ := uni.GetTranslator("zh")
	trans = transTemp
	// 注册中文翻译
	zh_translations.RegisterDefaultTranslations(validate, trans)
	// label tag返回字段名
	validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
		label := fld.Tag.Get("label")
		if label == "" {
			return fld.Name // 默认返回字段名
		}
		return label
	})
}

// 英文翻译器注册到校验器中
func enValidator() {
	en := en.New()
	uni = ut.New(en, en)
	transTemp, _ := uni.GetTranslator("en")
	trans = transTemp
	// 注册英文翻译
	en_translations.RegisterDefaultTranslations(validate, trans)
	// label tag返回字段名
	validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
		label := fld.Tag.Get("label")
		if label == "" {
			return fld.Name // 默认返回字段名
		}
		return label
	})
}

// 暴露出去，可进行独立的参数校验
func ValidateStruct(data any) error {
	// 判断是否有配置
	if fginConfig.Validator == "" {
		return errors.New("未配置validator项")
	}
	// 执行校验
	err := validate.Struct(data)
	if err != nil {
		// 转换错误类型并翻译
		if validationErrors, ok := err.(validator.ValidationErrors); ok {
			var errMsgs []string
			for _, e := range validationErrors {
				errMsgs = append(errMsgs, e.Translate(trans))
			}
			return errors.New(strings.Join(errMsgs, "; "))
		}
		return err
	}
	return nil
}
